home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
6912
/
6912.xpi
/
chrome
/
quickdrag.jar
/
content
/
quickdrag.js
next >
Wrap
Text File
|
2009-05-01
|
13KB
|
429 lines
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is QuickDrag.
*
* The Initial Developer of the Original Code is Kai Liu.
* Portions created by the Initial Developer are Copyright (C) 2008-2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kai Liu <kliu@code.kliu.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var QuickDragListener =
{
// The name of the event that we should listen to for drops
_drop: "drop",
handleEvent: function( evt )
{
var panel = gBrowser.mPanelContainer;
switch (evt.type)
{
case "load":
{
// Prior to the landing of the WHATWG drag API in Gecko 1.9.1,
// the event name was "dragdrop"
if ("getDragData" in nsDragAndDrop)
this._drop = "dragdrop";
window.removeEventListener(evt.type, this, false);
panel.addEventListener("dragstart", this, false);
panel.addEventListener("dragover", this, false);
panel.addEventListener(this._drop, this, false);
break;
}
case "unload":
{
window.removeEventListener(evt.type, this, false);
panel.removeEventListener("dragstart", this, false);
panel.removeEventListener("dragover", this, false);
panel.removeEventListener(this._drop, this, false);
break;
}
case "dragstart":
{
QuickDrag.dragstart(evt);
break;
}
case "dragover":
{
QuickDrag.dragover(evt);
break;
}
case this._drop:
{
QuickDrag.dragdrop(evt);
break;
}
}
}
};
var QuickDrag =
{
/**
* For a variety of reasons, the nsDragAndDrop JS wrapper is not suitable
* for this extension, but there are some pieces of nsDragAndDrop that are
* useful; these parts have been wrapped inside _session, _getDragData,
* and _securityCheck.
**/
// We want to know the "true" source of the drag, which we can no longer
// reliably get from the drag session in Gecko 1.9.1
_sourceNode: null,
// Wrapper for nsDragAndDrop.mDragSession
get _session( )
{
if (!nsDragAndDrop.mDragSession)
nsDragAndDrop.mDragSession = nsDragAndDrop.mDragService.getCurrentSession();
return(nsDragAndDrop.mDragSession);
},
// Wrapper for nsDragAndDrop.js's data retrieval; see nsDragAndDrop.drop
_getDragData: function( aEvent )
{
var data = "";
var type = "text/unicode";
if ("dataTransfer" in aEvent)
{
// Gecko 1.9.1 and newer: WHATWG drag-and-drop
// Try to get text/x-moz-url, if possible
data = aEvent.dataTransfer.getData("text/x-moz-url");
if (data.length != 0)
type = "text/x-moz-url";
else
data = aEvent.dataTransfer.getData("text/plain");
}
else if ("getDragData" in nsDragAndDrop)
{
// Gecko 1.9.0 and older: wrapper for nsDragAndDrop.getDragData
var flavourSet = new FlavourSet();
flavourSet.appendFlavour("text/x-moz-url");
flavourSet.appendFlavour("text/unicode");
var transferDataSet = nsTransferable.get(flavourSet, nsDragAndDrop.getDragData, true);
data = transferDataSet.first.first.data;
type = transferDataSet.first.first.flavour.contentType;
}
return({ data: data, type: type });
},
// Wrapper for nsDragAndDrop.dragDropSecurityCheck
_securityCheck: function( aEvent, aDragSession, aDraggedText )
{
if ("dragDropSecurityCheck" in nsDragAndDrop)
nsDragAndDrop.dragDropSecurityCheck(aEvent, aDragSession, aDraggedText);
else if ("dragDropSecurityCheck" in gBrowser)
gBrowser.dragDropSecurityCheck(aEvent, aDragSession, aDraggedText);
},
// Determine if two DOM nodes are from the same content area.
_fromSameContentArea: function( node1, node2 )
{
return(
node1 && node1.ownerDocument && node1.ownerDocument.defaultView &&
node2 && node2.ownerDocument && node2.ownerDocument.defaultView &&
node1.ownerDocument.defaultView.top.document ==
node2.ownerDocument.defaultView.top.document
);
},
// Is this an event that we want to handle?
_shouldHandleEvent: function( evt )
{
return(
( this._session.isDataFlavorSupported("text/unicode") ||
this._session.isDataFlavorSupported("text/plain") ) &&
( this._session.sourceNode == null ||
this._fromSameContentArea(this._session.sourceNode, evt.target) )
);
},
/**
* Event handlers
**/
dragstart: function( evt )
{
this._sourceNode = evt.explicitOriginalTarget;
},
dragover: function( evt )
{
if (!this._shouldHandleEvent(evt)) return;
this._session.canDrop = true;
},
dragdrop: function( evt )
{
if (!this._shouldHandleEvent(evt)) return;
// Load preferences; note that the pref is FG, but the var is BG
const prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch("extensions.quickdrag.");
var loadLinkInBG = !prefs.getBoolPref("loadLinkInFG") ^ evt.shiftKey;
var loadSearchInBG = !prefs.getBoolPref("loadSearchInFG") ^ evt.shiftKey;
var downloadImages = prefs.getBoolPref("downloadImages") || evt.altKey;
var linkOpenOverride = prefs.getBoolPref("linkOpenOverride");
// Get the source node and name
var sourceNode = this._session.sourceNode;
if (this._sourceNode)
{
sourceNode = this._sourceNode;
this._sourceNode = null;
}
var sourceName = (sourceNode) ? sourceNode.nodeName : "";
// Flags
var isURI = false;
var isImage = false;
var isAnchorLink = false;
// Parse the drag data
var dragData = this._getDragData(evt);
var lines = dragData.data.replace(/^\s+|\s+$/g, "").split(/\s*\n\s*/);
var str = lines.join(" ");
if (dragData.type == "text/x-moz-url")
{
// The user has dragged either a link or an image
// By default, we want to use the URI (the first line)
str = lines[0];
isURI = true;
if (sourceName == "IMG")
{
// Image or image link
isImage = true;
// If the URI does not match the source node, then this is a
// linked image (note that we DO want to treat images linked to
// themselves as if they are not linked at all)
if (sourceNode.src != str)
isAnchorLink = true;
}
else if (sourceName == "#text")
{
// Text link
isAnchorLink = true;
// The link's content text, condensed into one line
var text = lines.slice(1).join(" ");
// If appropriate, use the content text instead of the URI
if (!linkOpenOverride && text)
{
str = text;
isURI = false;
}
}
}
// Abort if we have no data; otherwise, proceed with URI detection
if (!str) return;
// Our heuristics; see bug 58 for info about the http fixup
var hasScheme = /^(?:(?:h?tt|hxx)ps?|ftp|chrome|file):\/\//i;
var hasIP = /(?:^|[\/@])(?:\d{1,3}\.){3}\d{1,3}(?:[:\/\?]|$)/;
var hasDomain = new RegExp(
// starting boundary
"(?:^|[:\\/\\.@])" +
// valid second-level name
"[a-z0-9](?:[a-z0-9-]*[a-z0-9])" +
// valid top-level name: ccTLDs + hard-coded [gs]TLDs
"\\.(?:[a-z]{2}|aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel)" +
// end boundary
"(?:[:\\/\\?]|$)",
// ignore case
"i"
);
isURI = isURI || hasScheme.test(str);
isURI = isURI || (!/\s/.test(str) && (hasIP.test(str) || hasDomain.test(str)));
if (isURI)
{
// The scheme fixup here is more relaxed; patterns that match this
// fixup but that failed the initial scheme heuristic are those
// that match a valid domain or IP address pattern
str = str.replace(/^(?:t?t|h[tx]{2,})p(s?:\/\/)/i, "http$1");
// Call dragDropSecurityCheck
this._securityCheck(evt, this._session, str);
// Treat drag as a middle click?
var mimicMiddleClick = isAnchorLink && linkOpenOverride;
// Send the referrer only for embedded images or emulated
// middle clicks over HTTP/HTTPS
var referrer = null;
if (sourceNode)
{
referrer = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService).
newURI(sourceNode.ownerDocument.location.href, null, null);
if (!((isImage || mimicMiddleClick) && /^https?$/i.test(referrer.scheme)))
referrer = null;
}
// Turn naked e-mail addresses into mailto: links
if (/^[\w\.\+\-]+@[\w\.\-]+\.[\w\-]{2,}$/.test(str))
str = "mailto:" + str;
// For image links, the we want to use the source URL unless we
// are going to treat the image as a link
if (isImage && (!mimicMiddleClick || evt.ctrlKey))
str = sourceNode.src;
if (isImage && !mimicMiddleClick && !evt.ctrlKey && downloadImages)
this._saveImage(str, referrer);
else if (!evt.altKey || (isImage && evt.ctrlKey) || !this._saveURL(str, referrer))
this._loadTab(str, referrer, null, loadLinkInBG);
}
else if (this._isSuite)
{
// Suite search
OpenSearch('qdsearch', str, true, evt.shiftKey);
}
else
{
// Firefox search
// Based on BrowserSearch::loadSearch in browser.js
const ss = Components.classes["@mozilla.org/browser/search-service;1"].
getService(Components.interfaces.nsIBrowserSearchService);
// Test to see if the search bar is active
var searchBarActive = false;
var searchBar = document.getElementById("searchbar");
if (searchBar)
{
var style = window.getComputedStyle(searchBar.parentNode, null);
if (style.visibility == "visible" && style.display != "none")
searchBarActive = true;
}
// If the search bar is visible, use the current engine;
// otherwise, fall back to the default engine
var engine = (searchBarActive) ? ss.currentEngine : ss.defaultEngine;
var submission = engine.getSubmission(str, null);
// Open the search in a new tab
this._loadTab(submission.uri.spec, null, submission.postData, loadSearchInBG);
}
evt.preventDefault();
evt.stopPropagation();
},
/**
* SeaMonkey compatibility
**/
// 0 == unknown, 1 == default (Firefox), 2 == suite (SeaMonkey)
_browserType: 0,
// true == SeaMonkey, false == Firefox
get _isSuite( )
{
if (this._browserType == 0)
{
const xai = Components.classes["@mozilla.org/xre/app-info;1"].
getService(Components.interfaces.nsIXULAppInfo);
// Cache the result
this._browserType = (xai.ID == "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}") ? 2 : 1;
}
return(this._browserType == 2);
},
// Wrapper for loadOneTab/addTab
_loadTab: function( aURI, aReferrerURI, aPostData, aLoadInBackground )
{
if (this._isSuite)
gBrowser.addTab(aURI, aReferrerURI, null, !aLoadInBackground, 0);
else
gBrowser.loadOneTab(aURI, aReferrerURI, null, aPostData, aLoadInBackground, false);
},
// Wrapper for saveURL
_saveURL: function( aURL, aReferrer )
{
// Unlike _loadTab, we need to do the scheme fixup manually; the "." is
// omitted because example.org:80 is probably server:80, not scheme:80
if (!/^[a-z][\da-z+\-]*:/i.test(aURL))
aURL = aURL.replace(/^:*[\/\\\s]*/, "http://").replace(/^ht(tp:\/\/ftp\.)/i, "f$1");
// If the protocol is not supported, let it fall through to a new tab
if (!/^(?:https?|ftp):/i.test(aURL))
return(false);
if (this._isSuite)
saveURL(aURL, null, null, false, aReferrer);
else
saveURL(aURL, null, null, false, true, aReferrer);
return(true);
},
// Wrapper for saveImageURL
_saveImage: function( aURL, aReferrer )
{
if (this._isSuite)
saveImageURL(aURL, null, null, false, aReferrer);
else
saveImageURL(aURL, null, null, false, true, aReferrer);
}
};
window.addEventListener("load", QuickDragListener, false);
window.addEventListener("unload", QuickDragListener, false);